package com.qf.util;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
@Component
public class DBUtil {

    private static DruidDataSource dataSource;

    @Resource
    private Environment env;

    @PostConstruct
    public void init() {
        if (dataSource == null) {
            dataSource = new DruidDataSource();
            dataSource.setUrl(env.getProperty("spring.datasource.url"));
            dataSource.setUsername(env.getProperty("spring.datasource.username"));
            dataSource.setPassword(env.getProperty("spring.datasource.password"));
            dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));

            // 可选的Druid连接池配置
            dataSource.setInitialSize(Integer.parseInt(env.getProperty("spring.datasource.druid.initial-size", "5")));
            dataSource.setMinIdle(Integer.parseInt(env.getProperty("spring.datasource.druid.min-idle", "5")));
            dataSource.setMaxActive(Integer.parseInt(env.getProperty("spring.datasource.druid.max-active", "20")));
            dataSource.setMaxWait(Long.parseLong(env.getProperty("spring.datasource.druid.max-wait", "60000")));
        }
    }


    public static Connection getConnection() {
        Connection conn = null;
        try {
            // 不需要我们获得连接
            // 而是通过Druid获得
            conn = dataSource.getConnection();
        } catch (Exception e) {
            System.out.println("获得连接出异常!!!");
            e.printStackTrace();
        }
        return conn;
    }


    /**
     * 关闭所有流
     */
    public static void closeAll(Connection conn, Statement s) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (s != null) {
            try {
                s.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    public static void closeAll(Connection conn, Statement s, ResultSet rs) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (s != null) {
            try {
                s.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }


    /**
     * 封装查询方法,返回一个对象
     * 参数1 执行查询的SQL,预处理的,条件用?占位
     * select * from tb_user where id = ? and username = ? and password = ?
     * 参数2 结果要封装的类
     * 参数3 给?赋值,不定长参数,是数组
     * 1,admin,123456
     */
    public static <T> T selectOne(String sql, Class<T> t, Object... args) {
        Connection conn = getConnection();
        PreparedStatement ps = null;
        ResultSet rs = null;
        T target = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; args != null && i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            rs = ps.executeQuery();
            /**
             * 创建对象
             * 从数据库取出数据,并设置对象属性
             */
            while (rs.next()) {
                target = t.newInstance();
                Field[] declaredFields = t.getDeclaredFields();
                for (int i = 0; i < declaredFields.length; i++) {
                    Field field = declaredFields[i];
                    Object value = rs.getObject(field.getName());

                    // 破解私有
                    field.setAccessible(true);

                    // 给对象的该字段赋值
                    field.set(target, value);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeAll(conn, ps, rs);
        }
        return target;
    }

    /**
     * 封装查询方法，返回一个List集合
     *
     * @param sql  编写查询的SQL语句
     * @param t    封装结果的类
     * @param args 给?赋值,不定长参数,是数组
     * @param <T>  T
     * @return List<T>
     */
    public static <T> List<T> selectAll(String sql, Class<T> t, Object... args) {
        Connection conn = getConnection();
        PreparedStatement ps = null;
        ResultSet rs = null;
        T target = null;
        ArrayList<T> list = new ArrayList<>();
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; args != null && i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            rs = ps.executeQuery();
            /**
             * 创建对象
             * 从数据库取出数据,并设置对象属性
             */
            while (rs.next()) {
                target = t.newInstance();
                Field[] declaredFields = t.getDeclaredFields();
                for (int i = 0; i < declaredFields.length; i++) {
                    Field field = declaredFields[i];
                    Object value = rs.getObject(field.getName());

                    // 破解私有
                    field.setAccessible(true);

                    // 给对象的该字段赋值
                    field.set(target, value);
                }
                list.add(target);

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeAll(conn, ps, rs);
        }
        return list;
    }

    /**
     * 封装更新方法,返回一个boolean值,表示是否更新成功
     * 参数1 执行更新的SQL,预处理的,条件用?占位
     * update tb_user set username = ? where id = ?
     * 参数2 给?赋值,不定长参数,是数组
     * 1,admin
     */
    public static boolean update(String sql, Object... args) {
        Connection conn = getConnection();
        PreparedStatement ps = null;
        int num = 0;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; args != null && i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            num = ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeAll(conn, ps);
        }
        return num > 0 ? true : false;
    }

}
